package com.jack.cms.oss.core;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Map;

import org.apache.commons.codec.EncoderException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.jack.cms.config.properties.QiniuProperties;
import com.jack.cms.core.util.DateUtil;
import com.qiniu.api.auth.AuthException;
import com.qiniu.api.auth.digest.Mac;
import com.qiniu.api.config.Config;
import com.qiniu.api.io.IoApi;
import com.qiniu.api.io.PutExtra;
import com.qiniu.api.io.PutRet;
import com.qiniu.api.net.CallRet;
import com.qiniu.api.rs.PutPolicy;
import com.qiniu.api.rs.RSClient;
import com.qiniu.api.url.URLEscape;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.model.FileListing;
import com.qiniu.util.Auth;

import sun.misc.BASE64Decoder;

@SuppressWarnings("restriction")
public abstract class QiniuUtils {
	private static Logger logger = LoggerFactory.getLogger(QiniuUtils.class);

	public abstract QiniuProperties getProperties();

	/**
	 * 获取token
	 */
	public String getUptoken(QiniuParam param) {
		String uptoken = null;
		try {
			Mac mac = getUploadMac();
			// 请确保该bucket已经存在
			String bucketName = param.getBucketName();
			Integer expiresTime = param.getExpiresTime();
			PutPolicy putPolicy = new PutPolicy(bucketName);
			putPolicy.expires = expiresTime * 3600;
			uptoken = putPolicy.token(mac);
		} catch (AuthException e) {
			logger.error("", e);
		} catch (Exception e) {
			logger.error("", e);
		}
		return uptoken;
	}

	/**
	 * 上传 MultipartFile file
	 */
	public int upload(MultipartFile file, String key) {// key: "2-2.jpg";
		try {
			Mac mac = getUploadMac();
			// 请确保该bucket已经存在
			PutPolicy putPolicy = new PutPolicy(getProperties().getBucketName());
			String uptoken = putPolicy.token(mac);
			PutExtra extra = getExtra(key);

			InputStream reader = file.getInputStream();
			PutRet ret = IoApi.Put(uptoken, key, reader, extra);
			logger.info(JSON.toJSONString(ret));
			return ret.statusCode;
		} catch (Exception e) {
			logger.error("", e);
			return 599;
		}

	}

	protected Mac getUploadMac() {
		Config.ACCESS_KEY = getProperties().getAssessKey();
		Config.SECRET_KEY = getProperties().getSecretKey();
		Mac mac = new Mac(Config.ACCESS_KEY, Config.SECRET_KEY);
		return mac;
	}
	
	private PutExtra getExtra(String key) {
		PutExtra extra = new PutExtra();
		Map<String, String> params = Maps.newHashMap();
		params.put("x:fileName", key);
		params.put("x:uploadTime", DateUtil.getMsTime());
		extra.params = params;
		return extra;
	}

	/**
	 * 上传 File
	 * 
	 * @throws Exception
	 */
	public String upload(InputStream inpustream, String key) throws Exception {
		Mac mac = getUploadMac();
		// 请确保该bucket已经存在
		PutPolicy putPolicy = new PutPolicy(getProperties().getBucketName());
		String uptoken = putPolicy.token(mac);
		PutExtra extra = getExtra(key);
		PutRet ret = IoApi.Put(uptoken, key, inpustream, extra);
		if (ret.statusCode != HttpStatus.OK.value()) {
			logger.error(JSON.toJSONString(ret));
			throw new RuntimeException(ret.getKey());
		}
		return ret.getKey();
	}

	/**
	 * 上传 File
	 * 
	 * @throws Exception
	 */
	public String upload(String base64, String key) throws Exception {// key:
		Mac mac = getUploadMac();
		// 请确保该bucket已经存在
		PutPolicy putPolicy = new PutPolicy(getProperties().getBucketName());
		String uptoken = putPolicy.token(mac);
		PutExtra extra = getExtra(key);

		BASE64Decoder decoder = new BASE64Decoder();
		byte[] bytes1 = decoder.decodeBuffer(base64);
		ByteArrayInputStream stream = new ByteArrayInputStream(bytes1);

		PutRet ret = IoApi.Put(uptoken, key, stream, extra);
		stream.close();

		if (ret.statusCode != HttpStatus.OK.value()) {
			logger.error(JSON.toJSONString(ret));
			throw new RuntimeException(ret.getKey());
		}
		return ret.getKey();
	}


	/**
	 * 删除单个文件
	 */
	public void del(String key) {// key:"2-2.jpg"
		try {
			Mac mac = getUploadMac();
			RSClient client = new RSClient(mac);
			CallRet ret = client.delete(getProperties().getBucketName(), key);
			logger.info(JSON.toJSONString(ret));
		} catch (Exception e) {
			logger.error("", e);
		}
	}

	/**
	 * 复制单个文件
	 */
	public void copy(String srcKey, String destKey) {
		Mac mac = getUploadMac();
		RSClient client = new RSClient(mac);
		CallRet ret = client.copy(getProperties().getBucketName(), srcKey, getProperties().getBucketName(), destKey);
		logger.info(JSON.toJSONString(ret));
	}

	public FileListing list(String marker, int count) throws Exception {
		Auth auth = Auth.create(getProperties().getAssessKey(), getProperties().getSecretKey());
		BucketManager bucketManager = new BucketManager(auth, new Configuration());
		FileListing fileListing = bucketManager.listFiles(getProperties().getBucketName(), null, marker, count, null);
		return fileListing;
	}

	public String getUrl(String key) {
		return this.getUrl(key, null, null);
	}

	public String getUrl(String key, Integer w, Integer h) {
		String url = "";
		try {
			String type = getProperties().getQboxrsctlPrivate();
			url = buildUrl(getProperties().getDomain(), key);
			logger.info(String.format("publicUrl:%s", url));
			if (type.equals("1")) {
				// 私有空间
				Auth auth = Auth.create(getProperties().getAssessKey(), getProperties().getSecretKey());
				long expireInSeconds = 3600;// 1小时，可以自定义链接过期时间
				url = auth.privateDownloadUrl(url, expireInSeconds);
				logger.info(String.format("downloadUrl:%s", url));
			}
		} catch (Exception e) {
			logger.error("", e);
		}
		return url;
	}

	protected String buildUrl(String domain, String name) throws EncoderException {
		name = URLEscape.escape(name);
		if (domain.startsWith("http")) {
			return domain + "/" + name;
		} else {
			return "http://" + domain + "/" + name;
		}
	}

}
